package sgsi.model.entidades.espacios;

import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;

import sgsi.model.entidades.Articulo;
import sgsi.model.entidades.Cliente;
import sgsi.model.entidades.Palet;
import sgsi.model.entidades.TipoDeArticulo;
import sgsi.model.entidades.TipoDePalet;
import sgsi.model.entidades.auxiliares.BorradoLogico;

public class Ubicacion extends BorradoLogico {

	private int codigoUbicacion;
	private Set<Palet> palets;
	private float alto;
	private float ancho;
	private float profundidad;
	private float pesoMaximo;
	private Area area;
	private String nombre;
 

	public float getAlto() 
	{
		return alto;
	}

	public void setAlto(float alto) 
	{
		this.alto = alto;
	}

	public float getAncho() 
	{
		return ancho;
	}

	public void setAncho(float ancho) 
	{
		this.ancho = ancho;
	}

	public float getProfundidad() 
	{
		return profundidad;
	}

	public void setProfundidad(float profundidad) 
	{
		this.profundidad = profundidad;
	}

	public float getPesoMaximo() {
		return pesoMaximo;
	}

	public void setPesoMaximo(float pesoMaximo) {
		this.pesoMaximo = pesoMaximo;
	}

	public void setArea(Area area) {
		this.area = area;
	}

	public Area getArea() {
		return area;
	}

	public void setNombre(String nombre) {
		this.nombre = nombre;
	}

	public String getNombre() {
		return nombre;
	}
	
	public int cantidadDisponiblePara(TipoDePalet tipoDePalet, float alto, float peso)
    {
		int cantidadPorCapacidad;
		int cantidadPorPeso;
		
		if (palets == null || palets.isEmpty())
			cantidadPorCapacidad = cantidadMaximaQueSoportaPara(tipoDePalet);
		else {
			TipoDePalet tipoDePaletUbicacion = palets.iterator().next().getTipoDePalet();
			if (tipoDePaletUbicacion.equals(tipoDePalet))
				cantidadPorCapacidad = cantidadMaximaQueSoportaPara(tipoDePalet) - palets.size();
			else
				cantidadPorCapacidad = 0;
		}
		
		cantidadPorPeso = cantidadMaximaQueSoportaPorPesoPara(peso);
		
		if (! soportaLaAlturaDelPalet(alto))
			cantidadPorCapacidad = 0;
		return (cantidadPorCapacidad < cantidadPorPeso) ? cantidadPorCapacidad : cantidadPorPeso;		
    }
	
	private float sumatoriaDePesoDeLosPalets() {
		float pesoTotal = 0;
		
		for(Palet palet : palets)
		{
			pesoTotal += palet.getPeso();
		}
		
		return pesoTotal;
	}
	
	private int cantidadMaximaQueSoportaPorPesoPara(float peso) {
		float pesoOcupado = sumatoriaDePesoDeLosPalets();
		if (pesoOcupado > 0 && pesoMaximo > 0)
		{
			float diferencia = pesoMaximo - pesoOcupado;
			return (int) (diferencia / peso);
		}
			
		if (pesoMaximo == 0)
			return Integer.MAX_VALUE;
		
		return (int) (pesoMaximo / peso);
	}
	
	public int cantidadMaximaQueSoportaPara(TipoDePalet tipoDePalet)
    {		
        int alternativa1 = cantidadPalets(tipoDePalet, profundidad, ancho);
        int alternativa2 = cantidadPalets(tipoDePalet, ancho, profundidad);

        return (alternativa1 > alternativa2) ? alternativa1 : alternativa2;
    }

    private int cantidadPalets(TipoDePalet tipoDePalet, float profundidadUbicacion, float anchoUbicacion)
    {
    	float anchoPalet = tipoDePalet.getAncho();
    	float largoPalet = tipoDePalet.getLargo();
    	
        if (largoPalet > profundidadUbicacion || anchoPalet > anchoUbicacion)
            return 0;

        int cantidadLargo = (int) (profundidadUbicacion/largoPalet);
        float restoLargo = profundidadUbicacion%largoPalet;
        int cantidadRestoLargo = cantidadPalets(tipoDePalet, anchoUbicacion, restoLargo);
        
        int cantidadAncho = (int) (anchoUbicacion/anchoPalet);
        float restoAncho = anchoUbicacion%anchoPalet;
        int cantidadRestoAncho = cantidadPalets(tipoDePalet, restoAncho, profundidadUbicacion);
        
        int cantidadAdicional = (cantidadRestoLargo > cantidadRestoAncho) ? cantidadRestoLargo : cantidadRestoAncho;

        return (cantidadLargo * cantidadAncho) + cantidadAdicional; 
    }
    
    public boolean soportaLaAlturaDelPalet(float altoPalet)
    {
        return altoPalet <= alto;
    }

	public void setCodigoUbicacion(int codigoUbicacion) {
		this.codigoUbicacion = codigoUbicacion;
	}

	public int getCodigoUbicacion() {
		return codigoUbicacion;
	}

	public void setPalets(Set<Palet> palets) {
		this.palets = palets;
	}

	public Set<Palet> getPalets() {
		return palets;
	}
	
	public void quitarPalet(Palet palet) {
		palets.remove(palet);	
	}

	public void agregarPalet(Palet palet) {
		palets.add(palet);		
	}
	
	public boolean tienePaletsDelCliente(final Cliente cliente) {
		
		Palet palet = (Palet) CollectionUtils.find(palets, new Predicate() {
				public boolean evaluate(Object objeto) {
					Palet palet = (Palet) objeto;
					
					return palet.getCliente().equals(cliente);
				}
			}
		);				
		
		return palet != null;
	}
	
	public boolean tienePaletsDelTipoDeArticulo(final TipoDeArticulo tipoDeArticulo) {
		
		Palet palet = (Palet) CollectionUtils.find(palets, new Predicate() {
				public boolean evaluate(Object objeto) {
					Palet palet = (Palet) objeto;
					
					return palet.getArticulo().getTipoDeArticulo().equals(tipoDeArticulo);
				}
			}
		);				
		
		return palet != null;
	}
	
	public boolean tienePaletsDelArticulo(final Articulo articulo) {
		
		Palet palet = (Palet) CollectionUtils.find(palets, new Predicate() {
				public boolean evaluate(Object objeto) {
					Palet palet = (Palet) objeto;
					
					return palet.getArticulo().equals(articulo);
				}
			}
		);				
		
		return palet != null;
	}

	public float getEspacioOcupado() {
		if (palets.size() == 0)
			return 0;
		
		Palet palet = palets.iterator().next();		
		return palet.getTipoDePalet().getAncho() * palet.getTipoDePalet().getLargo() * palets.size();
	}

	@Override
	public boolean puedeSerBorrada() {
		return palets.isEmpty();
	}
}
